#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <sys/stat.h>
#include <stdlib.h>

// RK Vendor Storage IOCTL definitions
#define VENDOR_REQ_TAG      0x56524551
#define VENDOR_READ_IO      _IOW('v', 0x01, unsigned int)
#define VENDOR_WRITE_IO     _IOW('v', 0x02, unsigned int)  // 修正：写入使用0x02

// Vendor storage request structure (与demo保持一致)
struct rk_vendor_req {
    uint32_t tag;       // Must be VENDOR_REQ_TAG
    uint16_t id;        // Vendor storage ID
    uint16_t len;       // Data length
    uint8_t data[1];    // Flexible array member (实际大小由外部缓冲区决定)
};

// Device configuration structure
struct device_config {
    char device_type[16];
    char sn[32];
    char cmei[32];
    char device_key[128];
};

// Vendor storage ID definitions - 使用安全的自定义ID范围
#define VENDOR_ID_SN        16  // Custom: Serial Number (避免系统预定义ID 1-4)
#define VENDOR_ID_DEVICE_TYPE   17  // Custom: Device Type
#define VENDOR_ID_CMEI      18  // Custom: CMEI
#define VENDOR_ID_DEVICE_KEY    19  // Custom: Device Key

#define DEVICE_PATH "/dev/vendor_storage"
#define OUTPUT_DIR "/opt/zyhy/params"
#define OUTPUT_FILE "/opt/zyhy/params/device_config.yaml"

// Vendor storage read function
int vendor_storage_read(int fd, uint16_t id, void *data, uint16_t len)
{
    uint8_t p_buf[2048];  // 使用与demo相同的缓冲区大小
    struct rk_vendor_req *req;
    int ret;
    
    req = (struct rk_vendor_req *)p_buf;
    memset(req, 0, sizeof(p_buf));
    
    req->tag = VENDOR_REQ_TAG;
    req->id = id;
    req->len = 512;  // 使用与demo相同的最大读取长度
    
    ret = ioctl(fd, VENDOR_READ_IO, req);
    if (ret < 0) {
        fprintf(stderr, "Error: Failed to read vendor storage ID %d: %s\n", id, strerror(errno));
        return ret;
    }
    
    // req->len 现在包含实际读取的数据长度
    if (req->len > len) {
        req->len = len;
    }
    
    memcpy(data, req->data, req->len);
    return req->len;
}

// Read device configuration from vendor storage
int read_device_config(int fd, struct device_config *config)
{
    int ret;
    
    printf("Reading device configuration from vendor storage...\n");
    
    memset(config, 0, sizeof(*config));
    
    // Read Serial Number (ID 16) - 从自定义位置读取
    ret = vendor_storage_read(fd, VENDOR_ID_SN, config->sn, sizeof(config->sn) - 1);
    if (ret < 0) {
        fprintf(stderr, "Warning: Failed to read SN, using default\n");
        strcpy(config->sn, "66666666666666");
    } else {
        config->sn[ret] = '\0';  // Ensure null termination
        printf("✓ SN read successfully: %s\n", config->sn);
    }
    
    // Read Device Type (ID 17)
    ret = vendor_storage_read(fd, VENDOR_ID_DEVICE_TYPE, config->device_type, sizeof(config->device_type) - 1);
    if (ret < 0) {
        fprintf(stderr, "Warning: Failed to read device type, using default\n");
        strcpy(config->device_type, "591844");
    } else {
        config->device_type[ret] = '\0';  // Ensure null termination
        printf("✓ Device type read successfully: %s\n", config->device_type);
    }
    
    // Read CMEI (ID 18)
    ret = vendor_storage_read(fd, VENDOR_ID_CMEI, config->cmei, sizeof(config->cmei) - 1);
    if (ret < 0) {
        fprintf(stderr, "Warning: Failed to read CMEI, using default\n");
        strcpy(config->cmei, "6666666666666");
    } else {
        config->cmei[ret] = '\0';  // Ensure null termination
        printf("✓ CMEI read successfully: %s\n", config->cmei);
    }
    
    // Read Device Key (ID 19)
    ret = vendor_storage_read(fd, VENDOR_ID_DEVICE_KEY, config->device_key, sizeof(config->device_key) - 1);
    if (ret < 0) {
        fprintf(stderr, "Warning: Failed to read device key, using default\n");
        strcpy(config->device_key, "66666666666666666666666666666666666666666666666");
    } else {
        config->device_key[ret] = '\0';  // Ensure null termination
        printf("✓ Device key read successfully\n");
    }
    
    return 0;
}

// Create directory if it doesn't exist
int create_directory(const char *path)
{
    struct stat st = {0};
    
    if (stat(path, &st) == -1) {
        if (mkdir(path, 0755) == -1) {
            fprintf(stderr, "Error: Failed to create directory %s: %s\n", path, strerror(errno));
            return -1;
        }
        printf("✓ Created directory: %s\n", path);
    }
    
    return 0;
}

// Remove file immutable attribute
int remove_file_protection(const char *filepath)
{
    char cmd[512];
    snprintf(cmd, sizeof(cmd), "chattr -i \"%s\" 2>/dev/null", filepath);
    return system(cmd);
}

// Set file immutable attribute
int set_file_protection(const char *filepath)
{
    char cmd[512];
    snprintf(cmd, sizeof(cmd), "chattr +i \"%s\" 2>/dev/null", filepath);
    return system(cmd);
}

// Write configuration to YAML file
int write_yaml_config(struct device_config *config)
{
    FILE *fp;
    
    // Create output directory if it doesn't exist
    if (mkdir(OUTPUT_DIR, 0755) != 0 && errno != EEXIST) {
        fprintf(stderr, "Error: Failed to create directory %s: %s\n", OUTPUT_DIR, strerror(errno));
        return -1;
    }
    
    // Remove file protection if file exists
    if (access(OUTPUT_FILE, F_OK) == 0) {
        printf("Removing file protection...\n");
        remove_file_protection(OUTPUT_FILE);
    }
    
    // Open output file for writing
    fp = fopen(OUTPUT_FILE, "w");
    if (!fp) {
        fprintf(stderr, "Error: Failed to open %s for writing: %s\n", OUTPUT_FILE, strerror(errno));
        return -1;
    }
    
    // Write YAML format
    fprintf(fp, "device:\n");
    fprintf(fp, "  deviceType: \"%s\"\n", config->device_type);
    fprintf(fp, "  SN: \"%s\"\n", config->sn);
    fprintf(fp, "  CMEI: \"%s\"\n", config->cmei);
    fprintf(fp, "  deviceKey: \"%s\"\n", config->device_key);
    
    fclose(fp);
    
    // Set file protection
    printf("Setting file protection...\n");
    set_file_protection(OUTPUT_FILE);
    
    printf("✓ Configuration written to: %s\n", OUTPUT_FILE);
    return 0;
}

int main(void)
{
    struct device_config config;
    int fd;
    
    printf("RK Vendor Storage Reader - Boot Service\n");
    printf("Author: Zhang Zhen <zhangzhen@cmhi.chinamobile.com>\n");
    printf("========================================\n\n");
    
    // Open vendor storage device
    fd = open(DEVICE_PATH, O_RDONLY);
    if (fd < 0) {
        fprintf(stderr, "Error: Cannot open %s: %s\n", DEVICE_PATH, strerror(errno));
        fprintf(stderr, "Using default configuration values\n");
        
        // Use default values if device is not accessible
        memset(&config, 0, sizeof(config));
        strcpy(config.device_type, "591844");
        strcpy(config.sn, "666666666666666");
        strcpy(config.cmei, "666666666666666");
        strcpy(config.device_key, "66666666666666666666666666666666666666");
    } else {
        // Read configuration from vendor storage
        if (read_device_config(fd, &config) != 0) {
            fprintf(stderr, "Error: Failed to read device configuration\n");
            close(fd);
            return 1;
        }
        close(fd);
    }
    
    // Write configuration to YAML file
    if (write_yaml_config(&config) != 0) {
        fprintf(stderr, "Error: Failed to write YAML configuration\n");
        return 1;
    }
    
    printf("\nDevice configuration successfully exported to %s\n", OUTPUT_FILE);
    return 0;
}
